//
//  KTask.h
//  Keping
//
//  Created by 柯平 on 2017/6/19.
//  Copyright © 2017年 柯平. All rights reserved.
//

#import <Foundation/Foundation.h>

@class KTask,KTaskManage;

#undef KTaskCancel
#define KTaskCancel()task) ({ if([(_task) isExecuting]) {[(_task) cancel]; } })

typedef NS_ENUM(signed short,KTaskState) {
    KTaskStateReady,        //准备完成的状态
    KTaskStateExecuting,    //task在运行中
    KTaskStateSuccess,      //task执行成功
    KTaskStateFailed,       //task执行失败
    KTaskStateCanceled      //task被取消
};

@protocol KTaskDelegate <NSObject>

//执行完成的回调方法，状态变为success或failed都会执行该方法，在主线程中或callBackQueue中执行
-(void)taskDidComplete:(KTask*)task;

@optional
//任务被取消时的回调通知，在主线程中或callBackQueue中执行
-(void)taskDidCancel:(KTask*)task;

@end

typedef void(^KTaskBlock)(KTask* task);

@interface KTask : NSOperation

//初始化
-(instancetype)initWithAttributes:(NSDictionary*)attributes  delegate:(id<KTaskDelegate>)delegate;

/**/
@property(nonatomic,strong)NSDictionary* attributes;

/**
 *  BBTaskDelegate中的方法执行的队列，当为nil时，使用main_queue执行回调函数
 */
@property (nonatomic, assign)   dispatch_queue_t callBackQueue;

@property (nonatomic, weak)   id<KTaskDelegate> delegate;
@property (nonatomic, copy)     KTaskBlock didCompleteBlock;
@property (nonatomic, copy)     KTaskBlock didCancelBlock;

/**
 *  是否在应用进入后台后继续运行， 默认是NO
 */
@property (nonatomic, assign) BOOL shouldContinueWhenAppEntersBackground;

/**
 *  标识当前的状态
 */
@property (readonly) KTaskState state;
@property (readonly) BOOL        isSuccessed;
@property (readonly) BOOL        isExecutingOrSuccessed;
@property (nonatomic, strong)    NSError    *error;

/**
 *  在当前线程中开始执行
 */
- (void)start;

/**
 *  在队列NSOperation中开始执行
 */
- (void)startAsynchronous;

/**
 *  子类实现调用，通知任务已经完成，并且成功
 */
- (void)markAsFinished;

/**
 *  子类调用， 通知任务完成，且失败
 *
 *  @param error 失败的错误信息
 */
- (void)failWithError:(NSError *)error;

/**
 *  子类实现，在任务被取消之前执行一些事情
 */
- (void)cancelTask;

/**
 *  子类实现，入口方法，任务的具体逻辑实现
 */
- (void)executeOperation;

#pragma mark - utils

/**
 *  当在executeOperation中启动了NSTimer，或者NSConnection等事件源，可在executeOperation方法最后
 *  调用该方法来启动runloop进行监听事件源。
 */
- (void)runloopContinueRunsIfInBackground;

#pragma mark - Class methods

/**
 *  取消observer监听的所有任务
 *
 *  @param observer 监听者，即代理
 */
+ (void)safeReleaseTasksOfObserver:(id)observer;

/**
 *  将多个任务同时加入队列中执行
 *
 *  @param operationArr 多个任务组成的数组
 */
+ (void)asyncRunOperations:(NSArray *)operationArr;

@end
